﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

using agree.schema;

using alib;
using alib.BitArray;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Debugging;
using alib.Enumerable;
using alib.Reflection;
using alib.String;
using alib.Observable;

namespace agree
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public abstract class ParseSelector : identity_base, ρρTypeUtils
	{
		public ParseSelector(IIdentity prv, TypeUtils tu)
			: base(prv)
		{
			this.tu = tu;
		}

		///////////////////////////////////////////////////////////////////////
		/// 
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TypeUtils tu;
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public TypeUtils TypeUtils
		{
			get { return tu; }
			set { tu = value; }
		}
		/// 
		///////////////////////////////////////////////////////////////////////
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("n-best Parse Selector")]
	[Description("Select N-best parses")]
	public abstract class NBestParseSelector : ParseSelector
	{
		public NBestParseSelector(IIdentity prv, TypeUtils tu)
			: base(prv, tu)
		{
			this.N = int.MaxValue;
		}
		public int N { get; set; }
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("All parse selector")]
	public class AllParseSelector : ParseSelector
	{
		public AllParseSelector(IIdentity prv, TypeUtils tu)
			: base(prv, tu)
		{
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("Single parse selector")]
	public class SingleParseSelector : ParseSelector
	{
		public SingleParseSelector(IIdentity prv, TypeUtils tu)
			: base(prv, tu)
		{
		}

		public ICollection<IDerivation> Produce(ParseControl ctrl)
		{
			var all_drv = ctrl
							.Forest
							.Unpack
							.ValidateAll
							//.Where(d => d.ItemStartSymbol.Name == "root_strict")
							.ToArray();
			IDerivation drv;
			if (all_drv.Length == 0)
			{
				return all_drv;
				//throw new Exception(String.Format("No parses matched the root condition 'root_strict' for '{0}'", ctrl.ts_input.Text));
			}
			else if (all_drv.Length == 1)
			{
				drv = all_drv[0];
			}
			else
			{
				drv = all_drv[0];
				//drv = all_drv
				//	.FirstOrDefault(irm => (irm.Tfs)
				//		.MrsRels
				//		.Any(rel => tu.TypeNameOrStringValue(rel.Pred).Contains("_v_1_rel")));
			}

			if (drv == null)
				throw new Exception();
			return new UnaryCollection<IDerivation>(drv);
		}
	};


	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 
	/// </summary>
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DisplayName("MaxEnt parse selector")]
	public class MaxentParseSelector : NBestParseSelector
	{
		public MaxentParseSelector(IIdentity prv, TypeUtils tu, String s_maxent_model_file)
			: base(prv, tu)
		{
			//model = new MaxEntModel(this, s_maxent_model_file);
		}

		//MaxEntModel model;
#if false
		public override ICollection<IRootDerivation> Produce(ParseControl item_in)
		{
			if (N == 0)
				return Collection<IRootDerivation>.None;

			ParseControl chart = item_in.chart;
			if (N == 1)
			{
				var deriv = chart.ValidatedRootDerivations.ArgMax(irm => ScoringHelper.Score(irm, model));
				return new IRootDerivation[] { deriv };
			}
			ICollection<IRootDerivation> rgd = chart.ValidatedRootDerivations;

			int c = Math.Min(rgd.Count, N);
			IRootDerivation[] arr;
			ArrayShrink<IRootDerivation> ars;
			if ((arr = chart.ValidatedRootDerivations as IRootDerivation[]) != null)
			{ }
			else if ((ars = rgd as ArrayShrink<IRootDerivation>) != null)
				arr = ars.GetArray();
			else
				throw new Exception("add a case for this item type");

			double[] scores = new double[c];
			for (int i = 0; i < c; i++)
				scores[i] = -ScoringHelper.Score(arr[i], model);

			Array.Sort(scores, arr, 0, c);

			return arr.Length == c ? (ICollection<IRootDerivation>)arr : new ArrayShrink<IRootDerivation>(arr, c);
		}
#endif
	};
}